package aino;


import java.io.*;

public class Pic extends CodeGen {

    static int strnumber = 0;

    public Pic(PrintWriter file) {
	out = file;
    }

    boolean usedMethod(Method m, String name, String funcName) {
	int x;

	if (name.equals("<init>")) return true;
	if (name.equals("<clinit>")) return true;
	if (name.equals("main")) return true;
	if (name.equals("interrupt")) return true;
	if (funcName.equals("Math16_mul__V")) return Aino.mul;
	if (funcName.equals("Math16_div__V")) return Aino.div || Aino.mod;
	if (funcName.equals("Math16_add__V")) return Aino.mul;
	if (funcName.equals("Math16_setup__V")) return Aino.mul || Aino.div || Aino.mod;

	for (x = 0; x < Aino.mSize; x++) {
	    if (Aino.meths[x] == m) {
		for (int y = 0; y < Aino.mSize; y++)
		    if (Aino.callMatrix[y][x])
			return true;
		return false;
	    }
	}
	if (x == Aino.mSize) System.out.println("\n*** Error: Internal error!");
	return false;
    }

    public void compile(Method m) {
	String methodName = m.cls.getConst(m.nameIndex);
	int codelen = m.getCodeLength();
	int pc = 0;
	
	codeLines.clear();
	funcName = m.getMethodName();
	stkptr = 0;

	if (!usedMethod(m, methodName, funcName)) {
	    codeLines.addComment("*** Message: Method "+funcName+" not used. No code generated.");
	    codeLines.print(out);
	    return;
	}

	codeLines.addLabel(funcName);
	codeLines.addImportantLabel(funcName);

	if (methodName.equals("main")) {
	    codeLines.addLabel("main");
	    codeLines.addImportantLabel("main");
	} else if (methodName.equals("interrupt")) {
	    Aino.interrupts.add(funcName);
	    /****
	    codeLines.addLabel("interrupt");
	    codeLines.addImportantLabel("interrupt");
	    codeLines.addCode("movwf\t_W_TEMP");
	    codeLines.addCode("swapf\t_STATUS,0");
	    codeLines.addCode("movwf\t_STATUS_TEMP");
	    codeLines.addCode("movf\t_ACC,0");
	    codeLines.addCode("movwf\t_ACC_TEMP");
	    codeLines.addCode("movf\t4,0");
	    codeLines.addCode("movwf\t_FSR_TEMP");
	    ****/
	}

	while (pc < codelen) {
	    int codebyte = m.getCodeByte(pc);
	    if (codebyte < 0) codebyte += 256;

	    int lineno = m.getLineNumber(pc);

	    if (lineno != 0) {
		try {
		    codeLines.addComment(m.cls.sourceFile+"["+lineno+"]: "+
					 (String)m.cls.sourceLines.elementAt(lineno-1));
		} catch (Exception e) {
		    codeLines.addComment(m.cls.sourceFile+"["+lineno+"]");
		}
	    }

	    currentLabel = new String(funcName+"_"+pc);
	    codeLines.addLabel(currentLabel);
	    if (Aino.verbose) {
		codeLines.addComment(m.codeTable[codebyte][2]);
	    }

	    switch (codebyte) {
	    case 0x00: //nop
		break;
	    case 0x01: //aconst_null
		pushStack(new Stack(Stack.CONST, "0"));
		break;
	    case 0x02: //iconst_m1 = -1
		pushStack(new Stack(Stack.CONST, "255"));
		break;
	    case 0x03: //iconst_0
	    case 0x04: //iconst_1
	    case 0x05: //iconst_2
	    case 0x06: //iconst_3
	    case 0x07: //iconst_4
	    case 0x08: //iconst_5
		//printStack("iconst");
		pushStack(new Stack(Stack.CONST, ""+(codebyte-0x03)));
		//printStack("after iconst");
		break;
	    case 0x09: //lconst_0
	    case 0x0a: //lconst_1
		pushStack(new Stack(Stack.CONST, ""+(codebyte-0x09), 2));
		break;
	    case 0x10: //bipush
		pushStack(new Stack(Stack.CONST, ""+m.getCodeByte(pc+1)));
		break;
	    case 0x11: //sipush
		pushStack(new Stack(Stack.CONST, ""+m.getCodeShort(pc+1)));
		break;
	    case 0x12: //ldc
	    case 0x13: { //ldc_w
		int idx;
		if (codebyte == 0x12) idx = m.getCodeByte(pc+1);
		else idx = m.getCodeShort(pc+1);
		if (m.cls.pool[idx].tag == 8)
		    pushStack(new Stack(Stack.STRING, ""+m.cls.getConst(idx)));
		else 
		    pushStack(new Stack(Stack.CONST, ""+m.cls.getConst(idx)));
		break;
	    }
	    case 0x14: { //ldc2_w
		int idx = m.getCodeShort(pc+1);
		pushStack(new Stack(Stack.CONST, ""+m.cls.getConst(idx), 2));
		break;
	    }
	    case 0x15: //iload
		pushStack(new Stack(Stack.ADDR, funcName+"_loc+"+
				    m.getCodeByte(pc+1)));
		break;
	    case 0x16: //lload
		pushStack(new Stack(Stack.ADDR, funcName+"_loc+"+
				    m.getCodeByte(pc+1), 2));
		break;
	    case 0x19: //aload
		pushStack(new Stack(Stack.ADDR, funcName+"_loc+"+
				    m.getCodeByte(pc+1)));
		break;
	    case 0x1a: //iload_0
	    case 0x1b: //iload_1
	    case 0x1c: //iload_2
	    case 0x1d: //iload_3
		pushStack(new Stack(Stack.ADDR, funcName+"_loc+"+
				    (codebyte-0x1a)));
		break;
	    case 0x1e: //lload_0
	    case 0x1f: //lload_1
	    case 0x20: //lload_2
	    case 0x21: //lload_3
		pushStack(new Stack(Stack.ADDR, funcName+"_loc+"+
				    (codebyte-0x1e), 2));
		break;
	    case 0x2a: //aload_0
	    case 0x2b: //aload_1
	    case 0x2c: //aload_2
	    case 0x2d: //aload_3
		pushStack(new Stack(Stack.ADDR, funcName+"_loc+"+
				    (codebyte-0x2a)));
		break;
	    case 0x2e: //iaload
	    case 0x2f: //laload
	    case 0x34: //caload
	    case 0x35: //saload
	    case 0x32: { //aaload
		Stack index = popStack();
		Stack array = popStack();
		checkAcc();

		if (index.type == Stack.ACC) {
		    codeLines.addCode("movwf\t4");
		    if (codebyte == 0x2f)
			codeLines.addCode("addwf\t4,1");
		    loadAcc(array);
		    codeLines.addCode("addwf\t4,1");
		} else {
		    loadAcc(array);
		    codeLines.addCode("movwf\t4");
		    loadAcc(index);
		    codeLines.addCode("addwf\t4,1");
		    if (codebyte == 0x2f)
			codeLines.addCode("addwf\t4,1");
		}
		codeLines.addCode("movf\t0,0");
		if (codebyte != 0x2f) {
		    pushStack(new Stack(Stack.ACC, "after iaload"));
		} else {
		    codeLines.addCode("movwf\t_ACC");
		    codeLines.addCode("incf\t4,1");
		    codeLines.addCode("movf\t0,0");
		    pushStack(new Stack(Stack.ACC, "after laload", 2));
		}
		break;
	    }
	    case 0x33: { //baload
		Stack index = popStack();
		Stack array = popStack();
		if (array.type != Stack.ADDR) 
		    exit("Boolean array address not good");
		if (index.type != Stack.CONST) 
		    exit("Boolean array index must be constant");
		codeLines.addCode("movlw\t1");
		codeLines.addCode("btfss\t"+array.value+","+index.value);
		codeLines.addCode("clrw");
		pushStack(new Stack(Stack.ACC, 
				    "after fetch from boolean array"));
		break;
	    }
	    case 0x36: //istore
	    case 0x3a: { //astore
		Stack s = popStack();
		loadAcc(s);
		codeLines.addCode("movwf\t"+funcName+"_loc+"+
				  m.getCodeByte(pc+1));
		break;
	    }
	    case 0x37: { //lstore
		Stack s = popStack();
		loadAccLo(s);
		codeLines.addCode("movwf\t"+funcName+"_loc+"+
				  m.getCodeByte(pc+1)+"+1");
		loadAccHi(s);
		codeLines.addCode("movwf\t"+funcName+"_loc+"+
				  m.getCodeByte(pc+1));
		break;
	    }
	    case 0x3b: //istore_0
	    case 0x3c: //istore_1
	    case 0x3d: //istore_2
	    case 0x3e: { //istore_3
		Stack s = popStack();
		loadAcc(s);
		codeLines.addCode("movwf\t"+funcName+"_loc+"+
				  (codebyte-0x3b));
		break;
	    }
	    case 0x3f: //lstore_0
	    case 0x40: //lstore_1
	    case 0x41: //lstore_2
	    case 0x42: { //lstore_3
		Stack s = popStack();
		loadAccLo(s);
		codeLines.addCode("movwf\t"+funcName+"_loc+"+
				  (codebyte-0x3f+1));
		loadAccHi(s);
		codeLines.addCode("movwf\t"+funcName+"_loc+"+
				  (codebyte-0x3f));
		break;
	    }
	    case 0x4b: //astore_0
	    case 0x4c: //astore_1
	    case 0x4d: //astore_2
	    case 0x4e: { //astore_3
		Stack s = popStack();
		loadAcc(s);
		codeLines.addCode("movwf\t"+funcName+"_loc+"+
				  (codebyte-0x4b));
		break;
	    }
	    case 0x4f: //iastore
	    case 0x53: //aastore
	    case 0x55: //castore
	    case 0x56: //sastore
	    case 0x50: { //lastore
		if (getStack().type == Stack.ACC) 
		    checkAcc();
		Stack element = popStack();
		Stack index = popStack();
		Stack table = popStack();
		checkAcc();
		if (index.type == Stack.ACC) {
		    codeLines.addCode("movwf\t4");
		    if (codebyte == 0x50)
			codeLines.addCode("addwf\t4,1");
		    loadAcc(table);
		    codeLines.addCode("addwf\t4,1");
		} else {
		    loadAcc(table);
		    codeLines.addCode("movwf\t4");
		    loadAcc(index);
		    codeLines.addCode("addwf\t4,1");
		    if (codebyte == 0x50)
			codeLines.addCode("addwf\t4,1");
		}
		if (codebyte == 0x50) {
		    loadAccHi(element);
		    codeLines.addCode("movwf\t0");
		    codeLines.addCode("incf\t4,1");
		    loadAccLo(element);
		    codeLines.addCode("movwf\t0");
		} else {
		    loadAcc(element);
		    codeLines.addCode("movwf\t0");
		}
		break;
	    }
	    case 0x54: { //bastore
		//printStack("bastore");
		Stack val = popStack();
		Stack index = popStack();
		Stack array = popStack();
		if (array.type != Stack.ADDR) exit("boolean array address not good");
		if (index.type != Stack.CONST) exit("boolean array index must be constant");
		if (val.type == Stack.CONST) {
		    if (val.value.equals("1"))
			codeLines.addCode("bsf\t"+array.value+","+index.value);
		    else
			codeLines.addCode("bcf\t"+array.value+","+index.value);
		} else {
		    if (val.type == Stack.ACC)
			codeLines.addCodeComment("iorlw\t0", "affect the Z flag");
		    loadAcc(val); // affect the Z flag!
		    codeLines.addCode("bsf\t"+array.value+","+index.value);
		    codeLines.addCodeComment("btfsc\t_STATUS,_Z", "test Z flag == 0");
		    codeLines.addCode("bcf\t"+array.value+","+index.value);
		}
		//printStack("after bastore");
	    break;
	    }
	    case 0x57: //pop
		popStack();
		break;
	    case 0x58: //pop2
		popStack();
		popStack();
		break;
	    case 0x59: { //dup
		checkAcc();
		Stack a = popStack();
		if (a.size == 1) {
		    pushStack(new Stack(a));
		} else exit("dup");
		pushStack(a);
		break;
	    }
	    case 0x5a: { //dup_x1
		checkAcc();
		Stack a = popStack();
		Stack b = popStack();
		if (a.size == 1 && b.size == 1) 
		    pushStack(new Stack(a));
		else exit("dup_x1");
		pushStack(b);
		pushStack(a);
		break;
	    }
	    case 0x5b: { //dup_x2
		checkAcc();
		Stack a = popStack();
		Stack b = popStack();
		if (a.size == 1 && b.size == 1) {
		    Stack c = popStack();
		    pushStack(new Stack(a));
		    pushStack(c);
		} else if (a.size == 1 && b.size == 2) {
		    pushStack(new Stack(a));
		} else exit("dup_x2");
		pushStack(b);
		pushStack(a);
		break;
	    }
	    case 0x5c: { //dup2
		checkAcc();
		Stack a = popStack();
		if (a.size == 1) {
		    Stack b = popStack();
		    pushStack(new Stack(b));
		    pushStack(new Stack(a));
		    pushStack(b);
		} else {
		    pushStack(new Stack(a));
		}
		pushStack(a);
		break;
	    }
	    case 0x5d: { //dup2_x1
		//printStack();
		checkAcc();
		Stack a = popStack();
		Stack b = popStack();
		if (a.size == 1 && b.size == 1) {
		    Stack c = popStack();
		    pushStack(new Stack(b));
		    pushStack(new Stack(a));
		    pushStack(c);
		} else if (a.size == 2 && b.size == 1) {
		    pushStack(new Stack(a));
		} else exit("dup2_x1");
		pushStack(b);
		pushStack(a);
		break;
	    }
	    case 0x5e: { //dup2_x2
		checkAcc();
		Stack a = popStack();
		Stack b = popStack();
		if (a.size == 2 && b.size == 2) {
		    pushStack(new Stack(a));
		} else {
		    Stack c = popStack();
		    if (a.size == 1 && b.size == 1 && c.size == 2) {
			pushStack(new Stack(b));
			pushStack(new Stack(a));
			pushStack(c);
		    } else if (a.size == 2 && b.size == 1 && c.size == 1) {
			pushStack(new Stack(a));
			pushStack(c);
		    } else {
			Stack d = popStack();
			if (a.size == 1 && b.size == 1 && 
			    c.size == 1 && d.size == 1) {
			    pushStack(new Stack(b));
			    pushStack(new Stack(a));
			    pushStack(d);
			    pushStack(c);
			}
		    }
		}
		pushStack(b);
		pushStack(a);
		break;
	    }
	    case 0x5f: { //swap
		Stack a = popStack();
		Stack b = popStack();
		pushStack(a);
		pushStack(b);
		break;
	    }
	    case 0x60: { //iadd
		Stack a = popStack();
		Stack b = popStack();
	    
		if (a.type == Stack.CONST) {
		    loadAcc(b);
		    codeLines.addCode("addlw\t"+a.value);
		} else if (b.type == Stack.CONST) {
		    loadAcc(a);
		    codeLines.addCode("addlw\t"+b.value);
		} else if (a.type == Stack.ADDR) {
		    loadAcc(b);
		    codeLines.addCode("addwf\t"+a.value+",0");
		} else if (b.type == Stack.ADDR) {
		    loadAcc(a);
		    codeLines.addCode("addwf\t"+b.value+",0");
		} 
		pushStack(new Stack(Stack.ACC, "after iadd"));
		break;
	    }
	    case 0x61: { //ladd
		codeLines.addComment("check acc");
		checkAcc();
		codeLines.addComment("pop a");
		Stack a = popStack();
		codeLines.addComment("pop b");
		Stack b = popStack();

		if (a.size != 2 || b.size != 2) {
		    exit("long add operands have wrong length");
		}
	    
		codeLines.addComment("load a hi");
		loadAccHi(a);

		if (b.type == Stack.CONST) {
		    int val = Integer.decode(b.value).intValue();
		    if (val > 255)
			codeLines.addCode("addlw\t"+(val>>8));
		    codeLines.addCode("movwf\t_ACC");
		    loadAccLo(a);
		    codeLines.addCode("addlw\t"+(val&0xff));
		    codeLines.addCode("btfsc\t_STATUS,_C");
		    codeLines.addCode("incf\t_ACC,1");
		} else if (b.type == Stack.ADDR) {
		    codeLines.addComment("start adding");
		    codeLines.addCode("addwf\t"+b.value2+",0");
		    codeLines.addCode("movwf\t_ACC");
		    codeLines.addComment("load a lo");
		    loadAccLo(a);
		    codeLines.addComment("continue adding");
		    codeLines.addCode("addwf\t"+b.value+",0");
		    codeLines.addCode("btfsc\t_STATUS,_C");
		    codeLines.addCode("incf\t_ACC,1");
		}
		codeLines.addComment("push to stack");
		pushStack(new Stack(Stack.ACC, "after ladd", 2));
		break;
	    }
	    case 0x64: { //isub
		Stack b = popStack();
		Stack a = popStack();
		if (a.type == Stack.CONST) {
		    loadAcc(b);
		    codeLines.addCode("sublw\t"+a.value);
		} else if (b.type == Stack.CONST) {
		    loadAcc(a);
		    codeLines.addCode("sublw\t"+b.value);
		    codeLines.addCode("sublw\t0");
		} else if (a.type == Stack.ADDR) {
		    loadAcc(b);
		    codeLines.addCode("subwf\t"+a.value+",0");
		} else if (b.type == Stack.ADDR) {
		    loadAcc(a);
		    codeLines.addCode("subwf\t"+b.value+",0");
		    codeLines.addCode("sublw\t0");
		}
		pushStack(new Stack(Stack.ACC, "after substraction"));
		break;
	    }
	    case 0x65: { //lsub
		checkAcc();
		// result = a - b
		Stack b = popStack();
		Stack a = popStack();

		if (a.size != 2 || b.size != 2) {
		    exit("long sub operands have wrong length");
		}
	    
		if (a.type == Stack.CONST) {
		    int val = Integer.decode(a.value).intValue();
		    loadAccHi(b);
		    codeLines.addCode("sublw\t"+(val>>8));
		    codeLines.addCode("movwf\t_ACC");
		    loadAccLo(b);
		    codeLines.addCode("sublw\t"+(val&0xff));
		    codeLines.addCode("btfss\t_STATUS,_C");
		    codeLines.addCode("decf\t_ACC,1");
		} else if (a.type == Stack.ADDR) {
		    if (b.type == Stack.ADDR) {
			loadAccHi(b);
			codeLines.addCode("subwf\t"+a.value2+",0");
			codeLines.addCode("movwf\t_ACC");
			loadAccLo(b);
			codeLines.addCode("subwf\t"+a.value+",0");
			codeLines.addCode("btfss\t_STATUS,_C");
			codeLines.addCode("decf\t_ACC,1");
		    } else if (b.type == Stack.CONST) {
			int val = - Integer.decode(b.value).intValue();
			loadAccHi(a);
			codeLines.addCode("addlw\t"+((val>>8)&0xff));
			codeLines.addCode("movwf\t_ACC");
			loadAccLo(a);
			codeLines.addCode("addlw\t"+(val&0xff));
			codeLines.addCode("btfsc\t_STATUS,_C");
			codeLines.addCode("incf\t_ACC,1");
		    } else {
			exit("lsub: operands not good");
		    }
		}
		pushStack(new Stack(Stack.ACC, "after lsub", 2));
		break;
	    }
	    case 0x68: { //imul
		checkAcc();
		Stack a = popStack();
		Stack b = popStack();
		loadAcc(a);
		codeLines.addCode("movwf\tMath16_aLo");
		loadAcc(b);
		codeLines.addCode("movwf\tMath16_bLo");
		codeLines.addCode("clrf\tMath16_aHi");
		codeLines.addCode("clrf\tMath16_bHi");
		codeLines.addCode("call\tMath16_mul__V");
		codeLines.addCode("movf\tMath16_cLo,0");
		pushStack(new Stack(Stack.ACC, "after imul"));
		break;
	    }
	    case 0x69: { //lmul
		Stack a = popStack();
		checkAcc();
		Stack b = popStack();
		loadAccLo(a);
		codeLines.addCode("movwf\tMath16_aLo");
		loadAccHi(a);
		codeLines.addCode("movwf\tMath16_aHi");

		loadAccLo(b);
		codeLines.addCode("movwf\tMath16_bLo");
		loadAccHi(b);
		codeLines.addCode("movwf\tMath16_bHi");

		codeLines.addCode("call\tMath16_mul__V");
		codeLines.addCode("movf\tMath16_cHi,0");
		codeLines.addCode("movwf\t_ACC");
		codeLines.addCode("movf\tMath16_cLo,0");

		pushStack(new Stack(Stack.ACC, "after lmul", 2));
		break;
	    }
	    case 0x6c:   //idiv
	    case 0x70: { //irem
		checkAcc();
		Stack a = popStack();
		Stack b = popStack();
		loadAcc(a);
		codeLines.addCode("movwf\tMath16_aLo");
		loadAcc(b);
		codeLines.addCode("movwf\tMath16_bLo");
		codeLines.addCode("clrf\tMath16_aHi");
		codeLines.addCode("clrf\tMath16_bHi");
		codeLines.addCode("call\tMath16_div__V");
		if (codebyte == 0x6c)
		    codeLines.addCode("movf\tMath16_bLo,0");
		else
		    codeLines.addCode("movf\tMath16_cLo,0");
		pushStack(new Stack(Stack.ACC, "after idiv"));
		break;
	    }
	    case 0x6d:   //ldiv
	    case 0x71: { //lrem
		checkAcc();
		Stack a = popStack();
		Stack b = popStack();
		loadAcc(a);
		codeLines.addCode("movwf\tMath16_aLo");
		codeLines.addCode("movf\t_ACC,0");
		codeLines.addCode("movwf\tMath16_aHi");
		loadAcc(b);
		codeLines.addCode("movwf\tMath16_bLo");
		codeLines.addCode("movf\t_ACC,0");
		codeLines.addCode("movwf\tMath16_bHi");

		codeLines.addCode("call\tMath16_div__V");
		if (codebyte == 0x6d) {
		    codeLines.addCode("movf\tMath16_bHi,0");
		    codeLines.addCode("movwf\t_ACC");
		    codeLines.addCode("movf\tMath16_bLo,0");
		} else {
		    codeLines.addCode("movf\tMath16_cHi,0");
		    codeLines.addCode("movwf\t_ACC");
		    codeLines.addCode("movf\tMath16_cLo,0");
		}
		pushStack(new Stack(Stack.ACC, "after ldiv", 2));
		break;
	    }
	    case 0x74: { //ineg
		Stack a = popStack();
		loadAcc(a);
		codeLines.addCode("sublw\t0");
		pushStack(new Stack(Stack.ACC, "after ineg"));
		break;
	    }
	    case 0x75: { //lneg XXXXX BUGGY
		checkAcc();
		Stack a = popStack();
		loadAccHi(a);
		codeLines.addCode("sublw\t0");
		codeLines.addCode("movwf\t_ACC");
		loadAccLo(a);
		codeLines.addCode("sublw\t0");
		pushStack(new Stack(Stack.ACC, "after lneg", 2));
		break;
	    }
	    case 0x7a: //ishr
	    case 0x7c: //iushr
	    case 0x78: { //ishl
		boolean left = codebyte == 0x78;
		Stack bits = popStack();
		Stack shifted = popStack();
		checkAcc();
		if (bits.type == Stack.CONST &&
		    bits.value.equals("0")) {
		    loadAcc(shifted);
		} else if (bits.type == Stack.CONST &&
		    bits.value.equals("1")) {
		    codeLines.addCode("bcf\t_STATUS,_C");
		    if (shifted.type != Stack.ADDR) {
			loadAcc(shifted);
			codeLines.addCode("movwf\t4");
			if (left) {
			    codeLines.addCode("rlf\t4,0");
			} else {
			    codeLines.addCode("rrf\t4,0");
			}
		    } else {
			if (left) {
			    codeLines.addCode("rlf\t"+shifted.value+",0");
			} else {
			    codeLines.addCode("rrf\t"+shifted.value+",0");
			}
		    }
		} else if (bits.type == Stack.CONST &&
			   bits.value.equals("4")) {
		    if (shifted.type != Stack.ADDR) {
			loadAcc(shifted);
			codeLines.addCode("movwf\t4");
			codeLines.addCode("swapf\t4,0");
		    } else {
			codeLines.addCode("swapf\t"+shifted.value+",0");
		    }
		    if (left) {
			codeLines.addCode("andlw\t240"); // 0xf0
		    } else {
			codeLines.addCode("andlw\t15"); // 0x0f
		    }
		} else {
		    String addr;
		    if (shifted.type == Stack.ACC) {
			codeLines.addCode("movwf\t_ACC");
			loadAcc(bits);
			codeLines.addCode("btfsc\t_STATUS,_Z");
			codeLines.addCode("goto\t"+currentLabel+"_end1");
			codeLines.addCode("movwf\t4");
		    } else {
			if (bits.type != Stack.ACC) {
			    loadAcc(bits);
			} else {
			    codeLines.addCode("iorlw\t0");
			}
			codeLines.addCode("btfsc\t_STATUS,_Z");
			codeLines.addCode("goto\t"+currentLabel+"_end2");

			codeLines.addCode("movwf\t4");
			loadAcc(shifted);
			codeLines.addCode("movwf\t_ACC");
		    }
		    codeLines.addLabel(currentLabel+"_loop");
		    codeLines.addImportantLabel(currentLabel+"_loop");
		    codeLines.addCode("bcf\t_STATUS,_C");
		    if (left) {
			codeLines.addCode("rlf\t_ACC,1");
		    } else {
			codeLines.addCode("rrf\t_ACC,1");
		    }
		    codeLines.addCode("decfsz\t4,1");
		    codeLines.addCode("goto\t"+currentLabel+"_loop");

		    codeLines.addLabel(currentLabel+"_end1");
		    codeLines.addImportantLabel(currentLabel+"_end1");

		    codeLines.addCode("movf\t_ACC,0");
		    codeLines.addCode("goto\t"+currentLabel+"_end");

		    codeLines.addLabel(currentLabel+"_end2");
		    codeLines.addImportantLabel(currentLabel+"_end2");
		    loadAcc(shifted);

		    codeLines.addLabel(currentLabel+"_end");
		    codeLines.addImportantLabel(currentLabel+"_end");
		}
		pushStack(new Stack(Stack.ACC, "after ishift"));
		break;
	    }
	    case 0x79: //lshl
	    case 0x7b: //lshr
	    case 0x7d: { //lushr
		boolean left = codebyte == 0x79;
		Stack bits = popStack();
		Stack shifted = popStack();
		checkAcc();
		if (bits.type == Stack.CONST &&
		    bits.value.equals("1")) {
		    loadAcc(shifted);
		    int freeTmp = findFreeTmp();
		    if (freeTmp < 0) {
			exit("No space for tmp vars ");
		    }
		    String addr = funcName+"_tmp+"+freeTmp;
		    codeLines.addCode("movwf\t"+addr);
		    codeLines.addCode("bcf\t_STATUS,_C");
		    if (left) {
			codeLines.addCode("rlf\t"+addr+",0");
			codeLines.addCode("rlf\t_ACC,1");
		    } else {
			codeLines.addCode("rrf\t_ACC,1");
			codeLines.addCode("rrf\t"+addr+",0");
		    }
		} else if (bits.type == Stack.CONST &&
			   bits.value.equals("8")) {
		    if (left) {
			loadAccLo(shifted);
			codeLines.addCode("movwf\t_ACC");
			codeLines.addCode("clrw");
		    } else {
			loadAccHi(shifted);
			codeLines.addCode("clrf\t_ACC");
		    }
		} else {
		    String addr;
		    if (shifted.type == Stack.ACC) {
			int freeTmp = findFreeTmp();
			if (freeTmp < 0) {
			    exit("No space for tmp vars ");
			}
			addr = funcName+"_tmp+"+freeTmp;
			codeLines.addCode("movwf\t"+addr);
			loadAcc(bits);
			codeLines.addCode("movwf\t4");
		    } else {
			if (bits.type != Stack.ACC)
			    loadAcc(bits);
			codeLines.addCode("movwf\t4");
			loadAcc(shifted);
			int freeTmp = findFreeTmp();
			if (freeTmp < 0) {
			    exit("No space for tmp vars ");
			}
			addr = funcName+"_tmp+"+freeTmp;
			codeLines.addCode("movwf\t"+addr);
		    }
		    codeLines.addCode("movlw\t15");
		    codeLines.addCode("andwf\t4,1");
		    codeLines.addCode("btfsc\t_STATUS,_Z");
		    codeLines.addCode("goto\t"+currentLabel+"_end");

		    codeLines.addLabel(currentLabel+"_loop");
		    codeLines.addImportantLabel(currentLabel+"_loop");
		    codeLines.addCode("bcf\t_STATUS,_C");
		    if (left) {
			codeLines.addCode("rlf\t"+addr+",1");
			codeLines.addCode("rlf\t_ACC,1");
		    } else {
			codeLines.addCode("rrf\t_ACC,1");
			codeLines.addCode("rrf\t"+addr+",1");
		    }
		    codeLines.addCode("decfsz\t4,1");
		    codeLines.addCode("goto\t"+currentLabel+"_loop");

		    codeLines.addLabel(currentLabel+"_end");
		    codeLines.addImportantLabel(currentLabel+"_end");
		    codeLines.addCode("movf\t"+addr+",0");
		}
		pushStack(new Stack(Stack.ACC, "after lshift", 2));
		break;
	    }
	    case 0x7e: { //iand
		Stack a = popStack();
		Stack b = popStack();
	    
		if (a.type == Stack.CONST) {
		    loadAcc(b);
		    codeLines.addCode("andlw\t"+a.value);
		} else if (b.type == Stack.CONST) {
		    loadAcc(a);
		    codeLines.addCode("andlw\t"+b.value);
		} else if (a.type == Stack.ADDR) {
		    loadAcc(b);
		    codeLines.addCode("andwf\t"+a.value+",0");
		} else if (b.type == Stack.ADDR) {
		    loadAcc(a);
		    codeLines.addCode("andwf\t"+b.value+",0");
		} 
		pushStack(new Stack(Stack.ACC, "after and"));
		break;
	    }
	    case 0x7f: { //land
		checkAcc();
		Stack a = popStack();
		Stack b = popStack();

		if (a.size != 2 || b.size != 2) {
		    exit("long or operands have wrong length");
		}
	    
		loadAccHi(a);

		if (b.type == Stack.CONST) {
		    int val = Integer.decode(b.value).intValue();
		    if (val > 255)
			codeLines.addCode("andlw\t"+(val>>8));
		    codeLines.addCode("movwf\t_ACC");
		    loadAccLo(a);
		    codeLines.addCode("andlw\t"+(val&0xff));
		} else if (b.type == Stack.ADDR) {
		    codeLines.addCode("andwf\t"+b.value2+",0");
		    codeLines.addCode("movwf\t_ACC");
		    loadAccLo(a);
		    codeLines.addCode("andwf\t"+b.value+",0");
		}
		pushStack(new Stack(Stack.ACC, "after land", 2));
		break;
	    }
	    case 0x80: { //ior
		Stack a = popStack();
		Stack b = popStack();
	    
		if (a.type == Stack.CONST) {
		    loadAcc(b);
		    codeLines.addCode("iorlw\t"+a.value);
		} else if (b.type == Stack.CONST) {
		    loadAcc(a);
		    codeLines.addCode("iorlw\t"+b.value);
		} else if (a.type == Stack.ADDR) {
		    loadAcc(b);
		    codeLines.addCode("iorwf\t"+a.value+",0");
		} else if (b.type == Stack.ADDR) {
		    loadAcc(a);
		    codeLines.addCode("iorwf\t"+b.value+",0");
		} 
		pushStack(new Stack(Stack.ACC, "after ior"));
		break;
	    }
	    case 0x81: { //lor
		checkAcc();
		Stack a = popStack();
		Stack b = popStack();

		if (a.size != 2 || b.size != 2) {
		    exit("long or operands have wrong length");
		}
	    
		loadAccHi(a);

		if (b.type == Stack.CONST) {
		    int val = Integer.decode(b.value).intValue();
		    if (val > 255)
			codeLines.addCode("iorlw\t"+(val>>8));
		    codeLines.addCode("movwf\t_ACC");
		    loadAccLo(a);
		    codeLines.addCode("iorlw\t"+(val&0xff));
		} else if (b.type == Stack.ADDR) {
		    codeLines.addCode("iorwf\t"+b.value2+",0");
		    codeLines.addCode("movwf\t_ACC");
		    loadAccLo(a);
		    codeLines.addCode("iorwf\t"+b.value+",0");
		}
		pushStack(new Stack(Stack.ACC, "after lor", 2));
		break;
	    }
	    case 0x82: { //ixor
		Stack a = popStack();
		Stack b = popStack();
	    
		if (a.type == Stack.CONST) {
		    loadAcc(b);
		    codeLines.addCode("xorlw\t"+a.value);
		} else if (b.type == Stack.CONST) {
		    loadAcc(a);
		    codeLines.addCode("xorlw\t"+b.value);
		} else if (a.type == Stack.ADDR) {
		    loadAcc(b);
		    codeLines.addCode("xorwf\t"+a.value+",0");
		} else if (b.type == Stack.ADDR) {
		    loadAcc(a);
		    codeLines.addCode("xorwf\t"+b.value+",0");
		} 
		pushStack(new Stack(Stack.ACC, "after xor"));
		break;
	    }
	    case 0x83: { //lxor
		checkAcc();
		Stack a = popStack();
		Stack b = popStack();

		if (a.size != 2 || b.size != 2) {
		    exit("long or operands have wrong length");
		}
	    
		loadAccHi(a);

		if (b.type == Stack.CONST) {
		    int val = Integer.decode(b.value).intValue();
		    if (val > 255)
			codeLines.addCode("xorlw\t"+(val>>8));
		    codeLines.addCode("movwf\t_ACC");
		    loadAccLo(a);
		    codeLines.addCode("xorlw\t"+(val&0xff));
		} else if (b.type == Stack.ADDR) {
		    codeLines.addCode("xorwf\t"+b.value2+",0");
		    codeLines.addCode("movwf\t_ACC");
		    loadAccLo(a);
		    codeLines.addCode("xorwf\t"+b.value+",0");
		}
		pushStack(new Stack(Stack.ACC, "after lxor", 2));
		break;
	    }
	    case 0x84: { //iinc
		int index = m.getCodeByte(pc+1);
		int value = m.getCodeByte(pc+2);
		if (value == 1) 
		    codeLines.addCode("incf\t"+funcName+"_loc+"+index+",1");
		else {
		    checkAcc();
		    codeLines.addCode("movlw\t"+value);
		    codeLines.addCode("addwf\t"+funcName+"_loc+"+index+",1");
		}
		break;
	    }
	    case 0x85: { //i2l
		Stack i = popStack();
		checkAcc();
		loadAcc(i);
		codeLines.addCode("clrf\t_ACC");
		pushStack(new Stack(Stack.ACC, "after i2l", 2));
		break;
	    }
	    case 0x88: //l2i
		stack[stkptr].size = 1;
		break;
	    case 0x91: //i2b
	    case 0x92: //i2c
	    case 0x93: //i2s
		// nothing to do
		break;
	    case 0x94: { //lcmp
		//printStack("lcmp");
		checkAcc();
		// result = a - b
		Stack val2 = popStack();
		Stack val1 = popStack();
		String pos = "1";
		String neg = "0xff";
		Stack a = val1;
		Stack b = val2;

		if (val2.type == Stack.CONST) {
		    a = val2;
		    b = val1;
		    pos = "0xff";
		    neg = "1";
		}

		if (a.size != 2 || b.size != 2) {
		    exit("long cmp operands have wrong length");
		}
	    
		if (a.type == Stack.CONST) {
		    int val = Integer.decode(a.value).intValue();
		    loadAccHi(b);
		    codeLines.addCode("sublw\t"+(val>>8));
		    codeLines.addCode("btfsc\t_STATUS,_Z");
		    codeLines.addCode("goto\t"+currentLabel+"_low_byte");

		    codeLines.addCode("movlw\t"+pos);
		    codeLines.addCode("btfss\t_STATUS,_C");
		    codeLines.addCode("movlw\t"+neg);
		    codeLines.addCode("goto\t"+currentLabel+"_end");

		    codeLines.addLabel(currentLabel+"_low_byte");
		    codeLines.addImportantLabel(currentLabel+"_low_byte");
		    loadAccLo(b);
		    codeLines.addCode("sublw\t"+(val&0xff));
		    codeLines.addCode("movlw\t0");
		    codeLines.addCode("btfsc\t_STATUS,_Z");
		    codeLines.addCode("goto\t"+currentLabel+"_end");

		    codeLines.addCode("movlw\t"+pos);
		    codeLines.addCode("btfss\t_STATUS,_C");
		    codeLines.addCode("movlw\t"+neg);
		    //codeLines.addCode("goto\t"+currentLabel+"_end");
		} else if (a.type == Stack.ADDR) {
		    if (b.type == Stack.ADDR) {
			loadAccHi(b);
			codeLines.addCode("subwf\t"+a.value2+",0");
			codeLines.addCode("btfsc\t_STATUS,_Z");
			codeLines.addCode("goto\t"+currentLabel+"_low_byte");

			codeLines.addCode("movlw\t"+pos);
			codeLines.addCode("btfss\t_STATUS,_C");
			codeLines.addCode("movlw\t"+neg);
			codeLines.addCode("goto\t"+currentLabel+"_end");

			codeLines.addLabel(currentLabel+"_low_byte");
			codeLines.addImportantLabel(currentLabel+"_low_byte");

			loadAccLo(b);
			codeLines.addCode("subwf\t"+a.value+",0");
			codeLines.addCode("movlw\t0");
			codeLines.addCode("btfsc\t_STATUS,_Z");
			codeLines.addCode("goto\t"+currentLabel+"_end");

			codeLines.addCode("movlw\t"+pos);
			codeLines.addCode("btfss\t_STATUS,_C");
			codeLines.addCode("movlw\t"+neg);
			//codeLines.addCode("goto\t"+currentLabel+"_end");
		    } else {
			exit("lsub: operands not good");
		    }
		}
		codeLines.addLabel(currentLabel+"_end");
		codeLines.addImportantLabel(currentLabel+"_end");
		pushStack(new Stack(Stack.ACC, "after lcmp"));
		//printStack("after lcmp");
		break;
	    }
	    case 0xc6: //ifnull
	    case 0xc7: //ifnonnull
	    case 0x99: //ifeq
	    case 0x9a: //ifne
	    case 0x9b: //iflt
	    case 0x9c: //ifge
	    case 0x9d: //ifgt
	    case 0x9e: //ifle
	    case 0x9f: //if_icmpeq
	    case 0xa0: //if_icmpne
	    case 0xa1: //if_icmplt
	    case 0xa2: //if_icmpge
	    case 0xa3: //if_icmpgt
	    case 0xa4: //if_icmple
	    case 0xa5: //if_acmpeq
	    case 0xa6: { //if_acmpne
		//  printStack("ifle");
		int offset = m.getSignCodeShort(pc+1);
		String jumpLabel = new String(funcName+"_"+(pc+offset));
		codeLines.addImportantLabel(jumpLabel);
		Stack b;
		Stack a;
		int cmp = cmdToCmp(codebyte);

		if (codebyte >= 0x9f && codebyte <= 0xa6) {
		    b = popStack();
		    a = popStack();
		} else {
		    a = popStack();

		    if (a.type == Stack.ACC)
			codeLines.addCode("iorlw\t0");
		    else
			loadAcc(a);

		    if (cmp == EQ || cmp == LE || cmp == GE) {
			codeLines.addCodeComment("btfsc\t_STATUS,_Z", 
						 "if eq");
			codeLines.addCode("goto\t"+jumpLabel);
			if (cmp == EQ) break;
		    } else if (cmp == NE) {
			codeLines.addCodeComment("btfss\t_STATUS,_Z", 
						 "if ne");
			codeLines.addCode("goto\t"+jumpLabel);
			break;
		    } else {
			codeLines.addCode("btfsc\t_STATUS,_Z");
			codeLines.addCode("goto\t$+4");
		    }

		    codeLines.addCode("andlw\t128");
		    if (cmp == GT || cmp == GE) {
			codeLines.addCode("btfsc\t_STATUS,_Z");
			codeLines.addCode("goto\t"+jumpLabel);
		    } else {
			codeLines.addCode("btfss\t_STATUS,_Z");
			codeLines.addCode("goto\t"+jumpLabel);
		    }
		    break;
		}

		if (a.type == Stack.CONST) {
		    loadAcc(b);
		    codeLines.addCode("sublw\t"+a.value);
		} else if (b.type == Stack.CONST) {
		    cmp = complementCmp(cmp);
		    loadAcc(a);
		    codeLines.addCode("sublw\t"+b.value);
		} else if (a.type == Stack.ADDR) {
		    loadAcc(b);
		    codeLines.addCode("subwf\t"+a.value+",0");
		} else if (b.type == Stack.ADDR) {
		    cmp = complementCmp(cmp);
		    loadAcc(a);
		    codeLines.addCode("subwf\t"+b.value+",0");
		}

		switch (cmp) {
		case EQ:
		    codeLines.addCodeComment("btfsc\t_STATUS,_Z", "skip if Z flag not set");
		    codeLines.addCodeComment("goto\t"+jumpLabel, "jump if eq");
		break;
		case NE:
		    codeLines.addCodeComment("btfss\t_STATUS,_Z", "skip if Z flag set");
		    codeLines.addCodeComment("goto\t"+jumpLabel, "jump if ne");
		    break;
		case GT:
		    codeLines.addCodeComment("btfsc\t_STATUS,_Z", "skip if Z flag not set");
		    codeLines.addCodeComment("goto\t$+3", "jump if eq");
		    codeLines.addCodeComment("btfsc\t_STATUS,_C", "skip if C flag not set");
		    codeLines.addCodeComment("goto\t"+jumpLabel, "jump if ge");
		    break;
		case GE:
		    codeLines.addCodeComment("btfsc\t_STATUS,_C", "skip if C flag not set");
		    codeLines.addCodeComment("goto\t"+jumpLabel, "jump if ge");
		    break;
		case LT:
		    codeLines.addCodeComment("btfss\t_STATUS,_C", "skip if C flag set");
		    codeLines.addCodeComment("goto\t"+jumpLabel, "jump if lt");
		    break;
		case LE:
		    codeLines.addCodeComment("btfsc\t_STATUS,_Z", "skip if Z flag not set");
		    codeLines.addCodeComment("goto\t"+jumpLabel, "jump if eq");
		    codeLines.addCodeComment("btfss\t_STATUS,_C", "skip if C flag set");
		    codeLines.addCodeComment("goto\t"+jumpLabel, "jump if lt");
		    break;
		}
		
		//printStack("after ifle");
		break;
	    }
	    case 0xa7: { //goto
		int offset = m.getSignCodeShort(pc+1);		
		String jumpLabel = new String(funcName+"_"+(pc+offset));
		codeLines.addImportantLabel(jumpLabel);
		codeLines.addCode("goto\t"+jumpLabel);
		break;
	    }
	    case 0xa8: { //jsr
		int offset = m.getSignCodeShort(pc+1);		
		String jumpLabel = new String(funcName+"_"+(pc+offset));
		codeLines.addImportantLabel(jumpLabel);
		codeLines.addCode("call\t"+jumpLabel);
		break;
	    }
	    case 0xa9: //ret
		exit("ret instruction");
		break;
	    case 0xaa: { //tableswitch
		int pos = pc + 1;
		while ((pos % 4) != 0) pos++;
		int def = m.getCodeInt(pos);
		pos += 4;
		int low = m.getCodeInt(pos);
		pos += 4;
		int high = m.getCodeInt(pos);
		pos += 4;
		Stack s = popStack();
		loadAcc(s);
		codeLines.addCode("movwf\t4");

		for (int i = low; i <= high; i++) {
		    int offset = m.getCodeInt(pos);
		    pos += 4;
		    codeLines.addCode("movf\t4,0");
		    codeLines.addCode("sublw\t"+i);
		    codeLines.addCode("btfsc\t_STATUS,_Z");
		    String jumpLabel = funcName+"_"+(pc+offset);
		    codeLines.addCode("goto\t"+jumpLabel);
		    codeLines.addImportantLabel(jumpLabel);
		}
		String jumpLabel = funcName+"_"+(pc+def);
		codeLines.addCode("goto\t"+jumpLabel);
		codeLines.addImportantLabel(jumpLabel);
		break;
	    }
	    case 0xab: { //lookupswitch
		int pos = pc + 1;
		while ((pos % 4) != 0) pos++;
		int def = m.getCodeInt(pos);
		pos += 4;
		int pairs = m.getCodeInt(pos);
		pos += 4;
		Stack s = popStack();
		loadAcc(s);
		codeLines.addCode("movwf\t4");
		for (int i = 0; i < pairs; i++) {
		    int match = m.getCodeInt(pos);
		    pos += 4;
		    int offset = m.getCodeInt(pos);
		    pos += 4;
		    codeLines.addCode("movf\t4,0");
		    codeLines.addCode("sublw\t"+match);
		    codeLines.addCode("btfsc\t_STATUS,_Z");
		    String jumpLabel = funcName+"_"+(pc+offset);
		    codeLines.addCode("goto\t"+jumpLabel);
		    codeLines.addImportantLabel(jumpLabel);
		}
		String jumpLabel = funcName+"_"+(pc+def);
		codeLines.addCode("goto\t"+jumpLabel);
		codeLines.addImportantLabel(jumpLabel);
		break;
	    }
	    case 0xac: //ireturn
	    case 0xad: //lreturn
	    case 0xb0: //areturn
		loadAcc(popStack());
	    case 0xb1: //return
		/****
		if (methodName.equals("interrupt")) {
		    codeLines.addCode("movf\t_FSR_TEMP,0");
		    codeLines.addCode("movwf\t4");
		    codeLines.addCode("movf\t_ACC_TEMP,0");
		    codeLines.addCode("movwf\t_ACC");
		    codeLines.addCode("swapf\t_STATUS_TEMP,0");
		    codeLines.addCode("movwf\t_STATUS");

		    codeLines.addCode("swapf\t_W_TEMP,1");
		    codeLines.addCode("swapf\t_W_TEMP,0");
		    codeLines.addCode("retfie");
		} else
		*****/
		codeLines.addCode("return");
		break;
	    case 0xb2: { //getstatic
		int index = m.getCodeShort(pc+1);

		if (m.cls.getDescriptor(index).equals("J"))
		    pushStack(new Stack(Stack.ADDR, m.cls.getClassName(index)+"_"+
					m.cls.getName(index), 2));
		else
		    pushStack(new Stack(Stack.ADDR, m.cls.getClassName(index)+"_"+
					m.cls.getName(index)));
		break;
	    }
	    case 0xb3: { //putstatic
		int index = m.getCodeShort(pc+1);

		Stack s = popStack();
		int len = 1;
		if (m.cls.getDescriptor(index).equals("J")) len = 2;
		if (len != s.size) exit("variable for putstatic has wrong type");

		loadAcc(s);
		if (len == 2) {
		    codeLines.addCode("movwf\t"+m.cls.getClassName(index)+"_"+
				      m.cls.getName(index)+"+1");
		    codeLines.addCode("movf\t_ACC,0");
		    codeLines.addCode("movwf\t"+m.cls.getClassName(index)+"_"+
				      m.cls.getName(index));
		} else {
		    codeLines.addCode("movwf\t"+m.cls.getClassName(index)+"_"+
				      m.cls.getName(index));
		}
		break;
	    }
	    case 0xb4: { //getfield
		int index = m.getCodeShort(pc+1);
		checkAcc();
		Stack instance = popStack();
		loadAcc(instance);
		codeLines.addCodeComment("addlw\t"+m.cls.getValidVarName(index),
					 "add offset for getfield");
		codeLines.addCode("movwf\t4");
		codeLines.addCodeComment("movf\t0,0", "getfield");
		if (m.cls.getDescriptor(index).equals("J")) {
		    codeLines.addCodeComment("movwf\t_ACC", "save the msb");
		    codeLines.addCodeComment("incf\t4,1", "pointer for the lsb");
		    codeLines.addCodeComment("movf\t0,0", "get lsb");
		    pushStack(new Stack(Stack.ACC, "after getfield", 2));
		} else {
		    pushStack(new Stack(Stack.ACC, "after getfield"));
		}
		break;
	    }
	    case 0xb5: { //putfield
		checkAcc();
		int index = m.getCodeShort(pc+1);
		Stack val = popStack();
		Stack obj = popStack();
		int len = 1;
		if (m.cls.getDescriptor(index).equals("J")) len = 2;
		if (len != val.size) exit("variable for putfield has wrong type");

		loadAcc(obj);
		codeLines.addCodeComment("addlw\t"+m.cls.getValidVarName(index),
					 "add field offset");
		codeLines.addCode("movwf\t4");
		if (len == 2) {
		    loadAccHi(val);
		    codeLines.addCodeComment("movwf\t0", "put the msb");
		    codeLines.addCodeComment("incf\t4,1", "pointer for the lsb");
		    loadAccLo(val);
		    codeLines.addCodeComment("movwf\t0", "put the lsb");
		} else {
		    loadAcc(val);
		    codeLines.addCodeComment("movwf\t0", "putfield");
		}
		break;
	    }
	    case 0xb6: //invokevirtual
	    case 0xb7: //invokespecial
	    case 0xb8: //invokestatic
	    case 0xb9: { //invokeinterface
		int index = m.getCodeShort(pc+1);
		String fname = m.cls.getValidFuncName(index);
		String a = m.cls.getDescriptor(index);
		String mName = m.cls.getName(index);
		int args = 1;
		Log.out("args = "+a);
		if (codebyte == 0xb8) args = 0;

		if (codebyte == 0xb9) {
		    args = m.getCodeByte(pc+3);
		} else {
		    int i = 1;
		    while (i < a.length() && a.charAt(i) != ')') {
			if (a.charAt(i) == 'L') {
			    int x;
			    for (x = i; a.charAt(x) != ';'; x++) ;
			    args++;
			    i = x + 1;
			} else if (a.charAt(i) == '[') {
			    i++;
			} else {
			    args++;
			    i++;
			}
		    }
		}
		Log.out("number of args = "+args);
		int returns;
		if (a.indexOf(")V") > 0) returns = 0;
		else if (a.indexOf(")J") > 0) returns = 2;
		else returns = 1;
		    
		if (mName.equals("_setMemory")) {
		    Stack val = popStack();
		    Stack addr = popStack();
		    checkAcc();
		    if (addr.type == Stack.CONST) {
			loadAcc(val);
			codeLines.addCode("movwf\t"+addr.value);
		    } else if (addr.type == Stack.ADDR) {
			if (val.type == Stack.ACC) {
			    codeLines.addCode("movwf\t_ACC");
			    loadAcc(addr);
			    codeLines.addCode("movwf\t4");
			    codeLines.addCode("movf\t_ACC,0");
			    codeLines.addCode("movwf\t0");
			} else {
			    loadAcc(addr);
			    codeLines.addCode("movwf\t4");
			    loadAcc(val);
			    codeLines.addCode("movwf\t0");
			}
		    } else if (addr.type == Stack.ACC) {
			codeLines.addCode("movwf\t4");
			loadAcc(val);
			codeLines.addCode("movwf\t0");
		    }
		} else if (mName.equals("_getMemory")) {
		    Stack addr = popStack();
		    checkAcc();
		    if (addr.type == Stack.CONST) {
			codeLines.addCode("movf\t"+addr.value+",0");
		    } else if (addr.type == Stack.ADDR) {
			loadAcc(addr);
			codeLines.addCode("movwf\t4");
			codeLines.addCode("movf\t0,0");
		    }
		} else if (mName.equals("_setBit") || 
			   mName.equals("_clearBit")) {
		    Stack bit = popStack();
		    Stack addr = popStack();

		    if (bit.type != Stack.CONST) {
			System.out.println("\n*** Error: Bit parameter must be constant");
		    } else {
			if (addr.type == Stack.CONST) {
			    if (mName.equals("_setBit"))
				codeLines.addCode("bsf\t"+addr.value+","+bit.value);
			    else
				codeLines.addCode("bcf\t"+addr.value+","+bit.value);
			} else {
			    checkAcc();
			    loadAcc(addr);
			    codeLines.addCode("movwf\t4");
			    if (mName.equals("_setBit"))
				codeLines.addCode("bsf\t0,"+bit.value);
			    else
				codeLines.addCode("bcf\t0,"+bit.value);
			}
		    }
		} else if (mName.equals("_delay")) {
		    Stack delay = popStack();
		    long dly = 1000;
		    int  nops = 3;
		    if (delay.type != Stack.CONST) {
			System.out.println("\n*** Error: _delay must have constant parameter");
			dly = 100;
		    } else {
			long d = Integer.decode(delay.value).longValue();
			for (nops = 3; nops < 14; nops++) {
			    dly = (d*(long)Aino.clockSpeed)/4000000L/nops;
			    if (dly < 256) break;
			}
		    }
		    if (dly < 256) {
			int codelines = 0;
			codeLines.addCode("movlw\t"+dly);
			codeLines.addCode("movwf\t_ACC");
			if (nops < 7) {
			    for (int i = 3; i < nops; i++, codelines++)
				codeLines.addCode("nop");
			} else {
			for (int i = 3; i < nops; i += 2, codelines++)
			    codeLines.addCode("goto\t$+1");
			}
			codeLines.addCode("decfsz\t_ACC,1");
			codeLines.addCode("goto\t$-"+(1+codelines));
		    } else {
			System.out.println("\n*** Error: Delay is too long, cannot generate code");
		    }
		} else if (mName.equals("_genlabel")) {
		    Aino.labels++;
		} else if (mName.equals("_getlabelhigh")) {
		    codeLines.addCode("movf\tHIGH(label"+Aino.labels+"),0");
		} else if (mName.equals("_getlabellow")) {
		    codeLines.addCode("movf\tLOW(label"+Aino.labels+"),0");
		} else if (mName.equals("_printlabel")) {
		    codeLines.addLabel("label"+Aino.labels);
		    codeLines.addImportantLabel("label"+Aino.labels);
		} else if (mName.equals("_asm")) {
		    for (int k = stkptr - args; k < stkptr; k++) {
			if (stack[k].type == Stack.STRING) {
			    codeLines.addCode("*"+stack[k].value);
			} else {
			    System.out.println("\n*** Error: Non-string parameter for _asm()!");
			}
		    }
		    stkptr -= args;
		} else if (fname.equals("_Str_charAt_I_C")) {
		    int strnum;
		    Stack pos = popStack();
		    Stack str = popStack();
		    checkAcc();
		    if (str.type == Stack.STRING) {
			loadAcc(pos);
			strnum = Aino.getStringNumber(str.value);
			codeLines.addCode("movwf\t_ACC");
			codeLines.addCode("incf\t_ACC,1");
			codeLines.addCode("movlw\tLOW strtable"+((strnum<0)?strnumber:strnum));
			codeLines.addCode("addwf\t_ACC,1");
			codeLines.addCode("movlw\tHIGH strtable"+((strnum<0)?strnumber:strnum));
			codeLines.addCode("btfsc\t_STATUS,_C");
			codeLines.addCode("addlw\t1");
			codeLines.addCode("movwf\t_PCLATH");
			codeLines.addCode("movf\t_ACC,0");

			if (strnum < 0) {
			    codeLines.addCode("call\tstrtable"+strnumber);
			    codeLines.addCode("goto\tstrtableend"+strnumber);

			    codeLines.addLabel("strtable"+strnumber);
			    codeLines.addImportantLabel("strtable"+strnumber);

			    codeLines.addCode("movwf\t_PCL");
			    for (int i = 0; i < str.value.length(); i++) {
				codeLines.addCode("retlw\t'"+str.value.charAt(i)+"'");
			    }
			    codeLines.addLabel("strtableend"+strnumber);
			    codeLines.addImportantLabel("strtableend"+strnumber);
			    strnumber++;
			    Aino.strings.add(str.value);
			} else {
			    codeLines.addCode("call\tstrtable"+strnum);
			}
		    } else {
			System.out.println("\n*** Error: Non-string parameter for charAt()!");
		    }
		} else if (fname.equals("_Str_length__I")) {
		    Stack str = popStack();
		    //checkAcc();
		    //codeLines.addCodeComment("movlw\t"+str.value.length(), "String.length()");
		    pushStack(new Stack(Stack.CONST, ""+str.value.length()));
		    returns = 0;
		} else if (fname.equals("_Str_toCharArray__AC")) {
		    Stack str = popStack();
		    checkAcc();
		    codeLines.addCode("movf\t_HEAP,0");
		    codeLines.addCode("movwf\t4");
		    for (int i = str.value.length()-1; i >= 0; i--) {
			codeLines.addCode("decf\t4,1");
			codeLines.addCode("movlw\t'"+str.value.charAt(i)+"'");
			codeLines.addCode("movwf\t0");
		    }

		    codeLines.addCode("movf\t4,0");
		    codeLines.addCode("movwf\t_HEAP");
		} else if (fname.equals("_Str_append_Str")) {
		    Stack str = popStack();
		    Stack strbuf = popStack();
		    checkAcc();
		    loadAcc(strbuf);
		    codeLines.addCode("movwf\t4");
		    codeLines.addCode("movf\t0,0"); // StringBuffer.buffer in W
		    codeLines.addCode("incf\t4,1");
		    codeLines.addCode("addwf\t0,0");
		    codeLines.addCode("movwf\t4");  // fsr points to append position
		    for (int i = 0; i < str.value.length(); i++) {
			codeLines.addCode("movlw\t'"+str.value.charAt(i)+"'");
			codeLines.addCode("movwf\t0");
			codeLines.addCode("incf\t4,1");
		    }
		    loadAcc(strbuf);
		    codeLines.addCode("movwf\t4");
		    codeLines.addCode("incf\t4,1");
		    codeLines.addCode("movlw\t"+str.value.length());
		    codeLines.addCode("addwf\t0,1");
		} else if (fname.equals("Task__init__Str")) {
		    Stack str = popStack();
		    Stack instance = popStack();
		    int dot = str.value.indexOf('.');
		    String cls = str.value.substring(0, dot);
		    String func = str.value.substring(dot+1);
		    String name = cls+"_"+func+"__V";
		    checkAcc();
		    loadAcc(instance);
		    codeLines.addCode("movwf\tTask__init__Str_loc+0");
		    codeLines.addCode("addlw\tTask_PC");
		    codeLines.addCode("movwf\t4");
		    codeLines.addCode("movlw\tHIGH "+name);
		    codeLines.addCode("movwf\t0");
		    codeLines.addCode("incf\t4,1");
		    codeLines.addCode("movlw\tLOW "+name);
		    codeLines.addCode("movwf\t0");
		    codeLines.addCode("call\t"+fname);
		} else if (fname.equals("Task_sleep_J_V")) {
		    Stack delay = popStack();
		    checkAcc();
		    codeLines.addCode("movf\tTask_current,0");
		    codeLines.addCode("addlw\tTask_timer");

		    codeLines.addCode("movwf\t4"); // timer high
		    loadAccHi(delay);
		    codeLines.addCode("movwf\t0");
		    codeLines.addCode("incf\t4,1"); // timer low
		    loadAccLo(delay);
		    codeLines.addCode("movwf\t0");
		    
		    Aino.labels++;
		    codeLines.addCode("incf\t4,1"); // PC high
		    codeLines.addCode("movlw\tHIGH label"+Aino.labels);
		    codeLines.addCode("movwf\t0");
		    codeLines.addCode("incf\t4,1"); // PC low
		    codeLines.addCode("movlw\tLOW label"+Aino.labels);
		    codeLines.addCode("movwf\t0");

		    codeLines.addCode("goto\tTask_schedule__V");

		    codeLines.addLabel("label"+Aino.labels);
		    codeLines.addImportantLabel("label"+Aino.labels);
		} else if ((mName.charAt(0) == '_' && !mName.equals("_init_")) ||
			   fname.startsWith("javaxlang")) {
		    stkptr -= args;
		} else {
		    moveFromStack(args, fname);
		    codeLines.addCode("call\t"+fname);
		}

		if (returns == 1) pushStack(new Stack(Stack.ACC, "returned value"));
		else if (returns == 2) pushStack(new Stack(Stack.ACC, "returned long value", 2));
		break;
	    }
	    case 0xba: //xxxunusedxxx
		exit("unused cmd");
		break;
	    case 0xbb: { //new
		int index = m.getCodeShort(pc+1);
		int class_name_index = m.cls.pool[index].value1;
		String class_name = m.cls.pool[class_name_index].str;
		Class c = Aino.getClass(class_name);
		if (c == null) exit("unknown class "+class_name);
		codeLines.addCode("movlw\t"+(c.instanceLen+
					     Aino.getSuperClassInstanceLength(c)));
		codeLines.addCode("subwf\t_HEAP,1");
		codeLines.addCode("movf\t_HEAP,0");
		pushStack(new Stack(Stack.ACC, "reference after new"));
		break;
	    }
	    case 0xbc: { //newarray
		int atype = m.getCodeByte(pc+1);
		checkAcc();
		Stack size = popStack();
		loadAcc(size);
		codeLines.addCode("subwf\t_HEAP,1");
		if (atype == 11) // long[] 
		    codeLines.addCode("subwf\t_HEAP,1");
		codeLines.addCode("movf\t_HEAP,0");
		pushStack(new Stack(Stack.ACC, "pointer to new array"));
		break;
	    }
	    case 0xbd: { //anewarray
		int index = m.getCodeShort(pc+1);
		int class_name_index = m.cls.pool[index].value1;
		String class_name = m.cls.pool[class_name_index].str;
		Class c = Aino.getClass(class_name);
		if (c == null) exit("unknown class "+class_name);

		checkAcc();
		Stack size = popStack();
		loadAcc(size); // size cannot be 0
		codeLines.addCode("movwf\t_ACC"); // array size to _ACC
		codeLines.addCode("movf\t_HEAP,0"); 
		codeLines.addCode("movwf\t4"); // current heap ptr to FSR

		codeLines.addCode("movf\t_ACC,0");
		codeLines.addCode("subwf\t_HEAP,1"); // decr heap to point to the table start

		// the loop
		codeLines.addLabel(currentLabel+"_loop");
		codeLines.addImportantLabel(currentLabel+"_loop");

		codeLines.addCode("movlw\t"+(c.instanceLen+
				  Aino.getSuperClassInstanceLength(c)));
		codeLines.addCode("subwf\t_HEAP,1"); // heap points to the start of the instance
		codeLines.addCode("movf\t_HEAP,0");
		codeLines.addCode("decf\t4,1"); // FSR points to the array slot
		codeLines.addCode("movwf\t0"); // store instance addr to the slot

		codeLines.addCode("decfsz\t_ACC,1");
		codeLines.addCode("goto\t"+currentLabel+"_loop");
		codeLines.addCode("movf\t4,0");

		pushStack(new Stack(Stack.ACC, "pointer to new class array"));
		break;
	    }
	    case 0xbe: //arraylength
		exit("arraylength not supported");
	    case 0xbf: //athrow
		exit("exceptions are not supported");
	    case 0xc0: //checkcast
		// always happy
		break;
	    case 0xc1: //instanceof
		exit("instanceof found");
	    case 0xc2: //monitorenter
	    case 0xc3: //monitorexit
		exit("threads are not supported");
	    case 0xc4: //wide
		exit("wide instruction not supported");
	    case 0xc5: //multianewarray
		exit("multidimensional arrays are not supported");
	    case 0xc8: { //goto_w
		int offset = m.getSignCodeInt(pc+1);		
		String jumpLabel = new String(funcName+"_"+(pc+offset));
		codeLines.addImportantLabel(jumpLabel);
		codeLines.addCode("goto\t"+jumpLabel);
		break;
	    }
	    case 0xc9: { //jsr_w
		int offset = m.getSignCodeInt(pc+1);		
		String jumpLabel = new String(funcName+"_"+(pc+offset));
		codeLines.addImportantLabel(jumpLabel);
		codeLines.addCode("call\t"+jumpLabel);
		break;
	    }
	    case 0xca: //breakpoint
	    case 0xfe: //impdep1
	    case 0xff: //impdep2
		exit("unimplemented code");
		break;
	    case 0x17: //fload
	    case 0x18: //dload
	    case 0x0b: //fconst_0
	    case 0x0c: //fconst_1
	    case 0x0d: //fconst_2
	    case 0x0e: //dconst_0
	    case 0x0f: //dconst_1
	    case 0x22: //fload_0
	    case 0x23: //fload_1
	    case 0x24: //fload_2
	    case 0x25: //fload_3
	    case 0x26: //dload_0
	    case 0x27: //dload_1
	    case 0x28: //dload_2
	    case 0x29: //dload_3
	    case 0x30: //faload
	    case 0x31: //daload
	    case 0x38: //fstore
	    case 0x39: //dstore
	    case 0x43: //fstore_0
	    case 0x44: //fstore_1
	    case 0x45: //fstore_2
	    case 0x46: //fstore_3
	    case 0x47: //dstore_0
	    case 0x48: //dstore_1
	    case 0x49: //dstore_2
	    case 0x4a: //dstore_3
	    case 0x51: //fastore
	    case 0x52: //dastore
	    case 0x62: //fadd
	    case 0x63: //dadd
	    case 0x66: //fsub
	    case 0x67: //dsub
	    case 0x6a: //fmul
	    case 0x6b: //dmul
	    case 0x6e: //fdiv
	    case 0x6f: //ddiv
	    case 0x72: //frem
	    case 0x73: //drem
	    case 0x76: //fneg
	    case 0x77: //dneg
	    case 0x86: //i2f
	    case 0x87: //i2d
	    case 0x89: //l2f
	    case 0x8a: //l2d
	    case 0x8b: //f2i
	    case 0x8c: //f2l
	    case 0x8d: //f2d
	    case 0x8e: //d2i
	    case 0x8f: //d2l
	    case 0x90: //d2f
	    case 0x95: //fcmpl
	    case 0x96: //fcmpg
	    case 0x97: //dcmpl
	    case 0x98: //dcmpg
	    case 0xae: //freturn
	    case 0xaf: //dreturn
		exit("Float and double not supported");
		break;
	    default:
		exit("Unknown op code");
	    }
	    pc = m.getNextPC(pc);
	}

	codeLines.print(out);
    }

}
